/**
 * @file
 * @author  michal.nezerka@gmail.com
 * @brief   Application Frame Implementation
 */

#include <iostream>

#include <wx/artprov.h>
#include <wx/dir.h>
#include <wx/filedlg.h>
#include <wx/filename.h>
#include <wx/imaglist.h>
#include <wx/listctrl.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/printdlg.h>
#include <wx/spinctrl.h>
#include <wx/srchctrl.h>
#include <wx/stdpaths.h>
#include <wx/textfile.h>
#include <wx/treectrl.h>

#include "version.h"
#include "mainwnd.h"
#include "preferencesdlg.h"
#include "latlondlg.h"

#if !defined(__WXMSW__) && !defined(__WXPM__)
    #include "wwicon.xpm"
#endif

using namespace wildwood;

//helper functions
enum wxbuildinfoformat
{
    short_f, long_f
};

class mmTreeItemData: public wxTreeItemData
{
public:
    mmTreeItemData(sqlite3_int64 dbId) : wxTreeItemData(), mDbId(dbId) { };
    sqlite3_int64 mDbId;
};

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__WXMAC__)
        wxbuild << _T("-Mac");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

enum
{
    idMenuFileDbNew,
    idMenuFileDbOpen,
    idCmdOpenDb,
    idMenuQuit = 1000,
    idMenuAbout,
    idMenuPreferences,
    idCmdGotoLatLon,
    idCmdGotoDefaultLoc,
    idCmdSetDefaultLoc,
    idMenuViewLog,
    idMenuViewTbMain,
};

BEGIN_EVENT_TABLE(MainWnd, wxFrame)
    EVT_MENU(wxID_NEW, MainWnd::OnFileNewSong)
    EVT_MENU(wxID_OPEN, MainWnd::OnFileOpenSong)
    EVT_MENU(idCmdOpenDb, MainWnd::OnOpenDb)
    EVT_MENU(idMenuQuit, MainWnd::OnQuit)
    EVT_MENU(idMenuAbout, MainWnd::OnAbout)
    EVT_CLOSE(MainWnd::OnClose)
    EVT_ERASE_BACKGROUND(MainWnd::OnEraseBackground)
    EVT_SIZE(MainWnd::OnSize)
    EVT_MENU(idMenuPreferences, MainWnd::OnPreferences)
    EVT_MENU(idCmdGotoLatLon, MainWnd::OnGotoLatLon)
    EVT_MENU(idCmdGotoDefaultLoc, MainWnd::OnGotoDefaultLoc)
    EVT_MENU(idCmdSetDefaultLoc, MainWnd::OnSetDefaultLoc)
    EVT_AUI_PANE_CLOSE(MainWnd::OnPaneClose)
END_EVENT_TABLE()

MainWnd::MainWnd(wxFrame *frame, const wxString& title)
    : wxFrame(frame, -1, title), mLogTextCtrl(NULL)
{
    SetIcon(wxICON(wwicon));

    // tell wxAuiManager to manage this frame
    m_auiMgr.SetManagedWindow(this);

    // create a menu bar
    wxMenuBar* mbar = new wxMenuBar();

    wxMenu* fileMenu = new wxMenu(_T(""));

    fileMenu->Append(idCmdOpenDb, wxT("Open database"), wxT("Open wildwood database"));
    fileMenu->AppendSeparator();
    fileMenu->Append(wxID_NEW, _("&New gpx"), _("Create a new song file"));
    fileMenu->Append(wxID_OPEN, _("&Open gpx..."), _("Open a song file"));
    fileMenu->AppendSeparator();
    fileMenu->Append(idMenuQuit, _("&Quit\tAlt-F4"), _("Quit the application"));

    mbar->Append(fileMenu, _("&File"));

    wxMenu* editMenu = new wxMenu(_T(""));
    editMenu->Append(idMenuPreferences, wxT("&Preferences..."), wxT("Application preferences"));
    mbar->Append(editMenu, _("&Edit"));

    wxMenu* viewMenu = new wxMenu(_T(""));
    viewMenu->Append(idCmdGotoLatLon, wxT("Go to coordinates..."), wxT("Go to coordinates (latitude, longitude)"));
    viewMenu->Append(idCmdGotoDefaultLoc, wxT("Go to default location"), wxT("Go to default location"));
    viewMenu->Append(idCmdSetDefaultLoc, wxT("Set default location"), wxT("Set current location as default location"));

    viewMenu->AppendSeparator();
    viewMenu->Append(idMenuViewLog, _("Log window"), _("View log window"), true);
    mbar->Append(viewMenu, _("&View"));

    wxMenu* helpMenu = new wxMenu(_T(""));
    helpMenu->Append(idMenuAbout, _("&About\tF1"), _("Show info about this application"));
    mbar->Append(helpMenu, _("&Help"));

    SetMenuBar(mbar);

    // -------------------- create the status bar
    // create a status bar with some information about the used wxWidgets version
    CreateStatusBar(2);
    SetStatusText(_("WildWood application"),0);
    SetStatusText(wxbuildinfo(short_f), 1);

    // -------------------- window size
    int top = wxGetApp().config->Read(_("/global/top"), 100);
    int left = wxGetApp().config->Read(_("/global/left"), 100);
    int width = wxGetApp().config->Read(_("/global/width"), 500);
    int height = wxGetApp().config->Read(_("/global/height"), 500);
    SetSize(left, top, width, height, 0);

    // create log window
    mLogTextCtrl = new wxTextCtrl(this, -1, wxEmptyString, wxPoint (0, 250), wxSize (700, 100), wxTE_MULTILINE);
    m_auiMgr.AddPane(mLogTextCtrl, wxAuiPaneInfo().Name(_("log")).Caption(wxT("Log")).Right().CloseButton(false).MinSize(200, wxDefaultCoord));

    // create map window
    mMapWnd = new MapWnd(this);
    m_auiMgr.AddPane(mMapWnd, wxAuiPaneInfo().Name(_("map")).Caption(wxT("Map")).Center().CloseButton(false));

    // create content window
    mGpxTree = new wxTreeCtrl(this);
    mGpxTree->AddRoot(wxT("Gpx"));
    m_auiMgr.AddPane(mGpxTree, wxAuiPaneInfo().Name(_("content")).Caption(wxT("Content")).Left().CloseButton(false).MinSize(200, wxDefaultCoord));

    // load perspective
    wxString perspective;
    if (wxGetApp().config->Read(_("/global/perspective"), &perspective))
    {
        m_auiMgr.LoadPerspective(perspective);

        GetMenuBar()->Check(idMenuViewLog, m_auiMgr.GetPane(mLogTextCtrl).IsShown());
    }

    m_auiMgr.Update();

    wxLogDebug(wxT("Main window initialized"));
}

MainWnd::~MainWnd()
{
    // save perspective
    wxGetApp().config->Write(_("/global/perspective"), m_auiMgr.SavePerspective());

    m_auiMgr.UnInit();
};

void MainWnd::OnClose(wxCloseEvent &event)
{
    // store window size
    int x, y;
    GetSize(&x, &y);
    wxGetApp().config->Write(_("/global/width"), x);
    wxGetApp().config->Write(_("/global/height"), y);
    GetPosition(&x, &y);
    wxGetApp().config->Write(_("/global/left"), x);
    wxGetApp().config->Write(_("/global/top"), y);

    Destroy();
}

void MainWnd::OnQuit(wxCommandEvent &event)
{
    Close();
}

void MainWnd::OnPreferences(wxCommandEvent &event)
{
    PreferencesDlg* dlg = new PreferencesDlg(0L, wxT("Wildwood Preferences"));

    if (dlg->ShowModal() == wxID_OK)
    {
        ;
    }
    dlg->Destroy();
}

void MainWnd::OnViewPane(wxCommandEvent& event)
{
    wxMenuBar *mBar = GetMenuBar();

    switch (event.GetId())
    {
        case idMenuViewLog:
            m_auiMgr.GetPane(mLogTextCtrl).Show(mBar->IsChecked(event.GetId()));
            break;
    }

    m_auiMgr.Update();
}

void MainWnd::OnAbout(wxCommandEvent &event)
{
    wxString msg = wxT("WildWood\n\n");
    msg += wxT("Yet another application for GPX editing.\n\n");
    msg += wxString::Format(wxT("Version: %d.%d\n\n"), WW_VERSION_MAJOR, WW_VERSION_MINOR);
    msg += wxbuildinfo(long_f);
    msg += wxT("\n\nFor more information visit project web page at:\nhttps://code.google.com/p/wildwood/");
    msg += wxT("\n\nAuthor: michal.nezerka@gmail.com");
    msg += wxT("\nhttp://blue.pavoucek.cz");

    wxMessageBox(msg, _("About WildWood"));
}

void MainWnd::OnPaneClose(wxAuiManagerEvent& evt)
{
    wxLogDebug(wxT("OnPaneClose for %s"), evt.pane->name.wc_str());

    /*if (evt.pane->name == _("file-browser"))
    {
        GetMenuBar()->Check(idMenuViewFileBrowser, false);
    }
    else if (evt.pane->name == _("song-editor"))
    {
        SetEditMode(false);
    }
    */
    m_auiMgr.Update();
}

void MainWnd::OnFileNewSong(wxCommandEvent& event)
{
    //sqlite3_int64 gpxId = wxGetApp().mGpxDb.createGpx();

    // add item to gpx tree
    mGpxTree->AppendItem(mGpxTree->GetRootItem(), wxT("Gpx file"));
    //mGpxTree->SetItemData(wxTreeItemId,
}

void MainWnd::OnFileOpenSong(wxCommandEvent& event)
{
    //wxFileName fileName(m_dirCtrl->GetPath());
    //wxString dir(fileName.GetPath());
    wxString dir = "/home/blue";
    wxFileDialog* openFileDialog = new wxFileDialog(this, _("Open file"), dir, _(""), _("*.gpx"), wxFD_OPEN, wxDefaultPosition);

    if (openFileDialog->ShowModal() == wxID_OK )
    {
        //OpenFile(openFileDialog->GetPath());
        //sqlite3_int64 gpxId = wxGetApp().mGpxDb.loadGpx(openFileDialog->GetPath());

        // add item to gpx tree
        mGpxTree->AppendItem(mGpxTree->GetRootItem(), wxT("Gpx file"));
    }
}

void MainWnd::OnOpenDb(wxCommandEvent& event)
{
    wxFileName docPath(wxStandardPaths::Get().GetUserDataDir());

    wxFileDialog* openFileDialog = new wxFileDialog(this, wxT("Open database"), docPath.GetFullPath(), wxT(""), wxT("*.wwdb"), wxFD_OPEN, wxDefaultPosition);

    if (openFileDialog->ShowModal() == wxID_OK )
    {
        wxGetApp().mGpxDb.open(openFileDialog->GetPath());
        wxGetApp().info(wxT("Opened wildwood database (sqlite)"));
    }

    delete openFileDialog;
}

void MainWnd::OnGotoLatLon(wxCommandEvent& event)
{
    LatLonDlg* dlg = new LatLonDlg(0L, wxT("Goto coordinates"), mMapWnd->getGeoPos().getLat(), mMapWnd->getGeoPos().getLon());

    if (dlg->ShowModal() == wxID_OK)
    {
        mMapWnd->setGeoPos(GeoPos(dlg->getLat(), dlg->getLon()));
        wxGetApp().info(wxT("Going to position (%f, %f)\n"), mMapWnd->getGeoPos().getLat(), mMapWnd->getGeoPos().getLon());
        mMapWnd->Refresh();
        mMapWnd->Update();
    }
    dlg->Destroy();
}

void MainWnd::OnGotoDefaultLoc(wxCommandEvent& event)
{
    mMapWnd->setGeoPos(wxGetApp().mSettings->mDefaultPos);
    wxGetApp().info(wxT("Going to default position (%f, %f)\n"), mMapWnd->getGeoPos().getLat(), mMapWnd->getGeoPos().getLon());
    mMapWnd->Refresh();
    mMapWnd->Update();
}

void MainWnd::OnSetDefaultLoc(wxCommandEvent& event)
{
    wxGetApp().info(wxT("Setting default position to (%f, %f)\n"), mMapWnd->getGeoPos().getLat(), mMapWnd->getGeoPos().getLon());
    wxGetApp().mSettings->mDefaultPos = mMapWnd->getGeoPos();
}

int updateGpxCallback(void *NotUsed, int argc, char **argv, char **azColName)
{
    int i;
    for(i = 0; i < argc; i++)
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}


void MainWnd::updateGpxTree()
{
    wxString sql(wxT("SELECT * FROM gpxs"));
    wxGetApp().mGpxDb.sqlExecute(sql, updateGpxCallback);
}

void MainWnd::addInfo(const wxString info)
{
    if (!mLogTextCtrl)
        return;
    mLogTextCtrl->AppendText(info);
}
